/**
 * Created by wangwenshan on 2020/4/14.
 */
import { AxiosRequestConfig,AxiosPromise,AxiosRespones } from '../types';
import { parseHeaders }  from '../helpers/headers';
import { createError } from '../helpers/error';

export default function xhr(config: AxiosRequestConfig): AxiosPromise{
    return new Promise((resolve, reject)=>{
        const { data = null, url, method = 'get', headers, responesType, timeout } = config;
        const request = new XMLHttpRequest()

        if(responesType){
            request.responseType = responesType
        }

        if(timeout){
            request.timeout = timeout
        }

        request.open(method.toUpperCase(), url!, true)
        request.onreadystatechange = function handleLoad() {
            if(request.readyState !== 4){
                return
            }

            if(request.status === 0){
                return
            }

            const responeHeaders = parseHeaders(request.getAllResponseHeaders())
            const responesData = responesType !== 'text' ? request.response : request.responseText
            const response: AxiosRespones = {
                data: responesData,
                status: request.status,
                statusText: request.statusText,
                headers: responeHeaders,
                config,
                request
            }
            handleResponse(response)
        }
        // 网络错误
        request.onerror = function handleError(){
            reject(createError('Network Error',config, null,request ))
        }
        // 超时
        request.ontimeout = function handleTimeout(){
            reject(createError(`Timeout of ${timeout} ms exceeded`,config, 'ECONNABORIED',request ))
        }

        headers && Object.keys(headers).forEach((name)=>{
            if(data === null && name.toLowerCase() === 'content-type'){
                delete headers[name]
            } else {
                request.setRequestHeader(name, headers[name])
            }
        });
        request.send(data)

        function handleResponse(response: AxiosRespones): void{
            if(response.status >= 200 && response.status < 300){
                resolve(response)
            } else {
                reject(createError(`Request failed with status code ${response.status}`,config, null,request,response ))
            }
        }
    })
}